package com.xneure.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import com.xneure.utils.bean.ClassFilter;

public class PackageUtil{
	/**
	 * 获取某包下（包括该包的所有子包）所有类
	 * 
	 * @param packageName 包名
	 * @return 类的完整名称
	 */
	public static List<String> getClassName(String packageName){
		return getClassName(packageName,new ClassFilter(){
			@Override
			public Class<?> filter(Class<?> class1){
				return class1;
			}
		});
	}

	/**
	 * 获取某包下所有类
	 * 
	 * @param packageName 包名
	 * @param ClassFilter 是否遍历子包
	 * @return 类的完整名称
	 */
	public static List<String> getClassName(String packageName,ClassFilter filter){
		List<String> fileNames = new ArrayList<String>(1000);
		ClassLoader loader = PackageUtil.class.getClassLoader();
		String packagePath = packageName.replace(".","/");
		try{
			Enumeration<URL> resourceUrls = loader.getResources(packagePath);
			while(resourceUrls.hasMoreElements()){
				URL url = resourceUrls.nextElement();
				if(url != null){
					if(url.getProtocol().equals("file")){
						fileNames.addAll(getClassNameByFile(url.getPath(),null,filter));
					}else if(url.getProtocol().equals("jar")){
						fileNames.addAll(getClassNameByJar(url.getPath(),filter));
					}
				}else{
					fileNames.addAll(getClassNameByJars(((URLClassLoader)loader).getURLs(),packagePath,filter));
				}
			}
		}catch(IOException e){
		}
		return fileNames;
	}

	/**
	 * 从项目文件获取某包下所有类
	 * 
	 * @param filePath 文件路径
	 * @param className 类名集合
	 * @param ClassFilter 是否遍历子包
	 * @return 类的完整名称
	 */
	private static List<String> getClassNameByFile(String filePath,List<String> className,ClassFilter filter){
		List<String> myClassName = new ArrayList<String>();
		File file = new File(filePath);
		File[] childFiles = file.listFiles();
		if(null != childFiles){
			for(File childFile:childFiles){
				if(childFile.isDirectory()){
					if(filter.filterChildPackage()){
						myClassName.addAll(getClassNameByFile(childFile.getPath(),myClassName,filter));
					}
				}else{
					String childFilePath = childFile.getPath();
					if(childFilePath.endsWith(".class")){
						childFilePath = childFilePath.substring(childFilePath.indexOf("\\classes") + 9,childFilePath.lastIndexOf("."));
						childFilePath = childFilePath.replace("\\",".");
						if(filter.pathMatch(childFilePath)){
							myClassName.add(childFilePath);
						}
					}
				}
			}
		}
		return myClassName;
	}

	/**
	 * 从jar获取某包下所有类
	 * 
	 * @param jarPath jar文件路径
	 * @param ClassFilter. 是否遍历子包
	 * @return 类的完整名称
	 */
	private static List<String> getClassNameByJar(String jarPath,ClassFilter filter){
		List<String> myClassName = new ArrayList<String>();
		String[] jarInfo = jarPath.split("!");
		String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
		String packagePath = jarInfo[1].substring(1);
		if(packagePath.equals("/")){
			packagePath = "";
		}
		try{
			@SuppressWarnings("resource")
			JarFile jarFile = new JarFile(jarFilePath);
			Enumeration<JarEntry> entrys = jarFile.entries();
			while(entrys.hasMoreElements()){
				JarEntry jarEntry = entrys.nextElement();
				if(jarEntry.isDirectory() == false){
					String entryName = jarEntry.getName();
					if(entryName.endsWith(".class") == false){
						continue;
					}
					if(filter.filterChildPackage()){
						if(entryName.startsWith(packagePath)){
							entryName = entryName.replace("/",".").substring(0,entryName.lastIndexOf("."));
							if(filter.pathMatch(entryName)){
								myClassName.add(entryName);
							}
						}
					}else{
						int index = entryName.lastIndexOf("/");
						String myPackagePath;
						if(index != -1){
							myPackagePath = entryName.substring(0,index);
						}else{
							myPackagePath = entryName;
						}
						if(myPackagePath.equals(packagePath)){
							entryName = entryName.replace("/",".").substring(0,entryName.lastIndexOf("."));
							if(filter.pathMatch(entryName)){
								myClassName.add(entryName);
							}
						}
					}
				}
			}
		}catch(Exception e){
		}
		return myClassName;
	}

	/**
	 * 从所有jar中搜索该包，并获取该包下所有类
	 * 
	 * @param urls URL集合
	 * @param packagePath 包路径
	 * @param ClassFilter 是否遍历子包
	 * @return 类的完整名称
	 */
	private static List<String> getClassNameByJars(URL[] urls,String packagePath,ClassFilter filter){
		List<String> myClassName = new ArrayList<String>();
		if(urls != null){
			for(int i = 0;i < urls.length;i++){
				URL url = urls[i];
				String urlPath = url.getPath();
				String jarPath = urlPath + "!/" + packagePath;
				myClassName.addAll(getClassNameByJar(jarPath,filter));
			}
		}
		return myClassName;
	}

	public static <T> List<Class<T>> getClassList(String packPath,Class<T> cls){
		return getClassList(packPath,new ClassFilter(){
			@Override
			public Class<?> filter(Class<?> c){
				if(cls.isAssignableFrom(c) && c.isInterface() == false && Modifier.isAbstract(c.getModifiers()) == false){
					return c;
				}
				return null;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public static <T> List<Class<T>> getClassList(String packPath,ClassFilter filter){
		ClassLoader classLoader = PackageUtil.class.getClassLoader();
		List<Class<T>> clsList = new ArrayList<Class<T>>(100);
		String[] paths = StrUtil.strToArray(packPath,",");
		for(String path:paths){
			if(ObjectUtil.isNull(path)){
				continue;
			}
			List<String> resourceUrls = PackageUtil.getClassName(path,filter);
			for(String s:resourceUrls){
				try{
					Class<?> c = filter.filter(classLoader.loadClass(s));
					if(null != c){
						clsList.add((Class<T>)c);
					}
				}catch(Throwable e){
				}
			}
		}
		return clsList;
	}
}
